#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/of.h>
#include <linux/of_gpio.h>

#include <linux/of_net.h>
#include <linux/ethtool.h>
#include <linux/dm9000.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/io.h>


int ds18_gpio = -1;



#define GPIO_DS18B20	ds18_gpio

#define DS18B20_IO_UP	gpio_set_value(GPIO_DS18B20, 1)
#define DS18B20_IO_DOWN		gpio_set_value(GPIO_DS18B20, 0)

#define DS18B20_OUT		gpio_direction_output(GPIO_DS18B20, 1)
#define DS18B20_IN		gpio_direction_input(GPIO_DS18B20)


static void ds18_write(uint16_t data )
{
	uint8_t i, temp;

	
 	DS18B20_OUT;
	
	for(i=0; i<8; i++)
	{
	 	temp = data & 0x01;
		data = data >> 1;
		
		if(temp)		 //写1
		{
		
			DS18B20_IO_DOWN;
			udelay(6); 
			DS18B20_IO_UP;
			udelay(64); 
		}           
	  else
		{
			DS18B20_IO_DOWN;
			udelay(60);
			DS18B20_IO_UP;
			udelay(10);
			 
		
		}
	}
	

}

static uint8_t ds18_read(void)	 //读位
{

	uint8_t data;
	
	DS18B20_OUT;
	
	DS18B20_IO_DOWN;
	
	udelay(6);
	
	DS18B20_IO_UP;
	
	DS18B20_IN;
	
	udelay(9);
	
	
	if(gpio_get_value(GPIO_DS18B20)==1){
	
		data =1;
	
	}else{

		data =0;
	}

  udelay(45);
  

  return data;
}


static uint8_t ds18_reads(void)
  {
   uint8_t i = 0,
   		   temp = 0,
   		   mydata = 0;
   
	  for(i=0;i<8;i++)
	  {
	   	  temp = ds18_read();
		  mydata = mydata | (temp<<i); 
	   
	  }
	  
  udelay(2);
	  
  return mydata;
  
  }


static uint8_t ds18_reset(void)
  {
	  

		DS18B20_OUT;
		DS18B20_IO_DOWN;
	
		udelay(300);
		
		udelay(300);
	
		DS18B20_IO_UP;
	      
		DS18B20_IN;  // 600 us

		udelay(100);
	
		if (gpio_get_value(GPIO_DS18B20) == 0){

			udelay(100);
			return 0;

			}
		
	printk("reset fail \n");
	
 	return -1;
  
  }

static uint8_t ds18_change(void)
{

	if (ds18_reset() != 0)goto error1;
	ds18_write(0xCC);
	udelay(1);
	ds18_write(0x44);     //转换温度

	return 0;

error1:
		printk("change error \n");
		return -1;

}


int long_to_char(uint32_t data,char *p)
{
	p[0] = data / 100000;

	data = data % 100000;

	p[1] = data / 10000;
	data = data % 10000;

	p[2] = data / 1000;
	data = data % 1000;

	p[3] = data / 100;
	data = data % 100;

	p[4] = data / 10;
	data = data % 10;

	p[5] = data ;

	return 0;
}


static uint32_t ds18b20_tmp(void)
{
	
	uint8_t tp_msb = 0,
			tp_lsb = 0;
			
			
	uint32_t data;


	if (ds18_reset() != 0)goto error1;
	ds18_write(0xCC);
	udelay(1);
	ds18_write(0x44);     //转换温度
			
	msleep(500);

		
	if (ds18_reset() != 0)goto error1;
	ds18_write(0xCC);
	udelay(1);
	ds18_write(0xBE);   //读取温度

	tp_lsb=	 ds18_reads();
	udelay(1);
	tp_msb=	 ds18_reads();
		
	data = tp_msb<<8;
	data = data | tp_lsb;
	
	if( data < 0 )		
		data = (~data+1) * 625;	
	else
		data = data * 625;  

		//printk("nk_tmp = %d \n", data);
	
	
	return data;
	
	error1:
		printk("read error \n");
		return -1;


}


static long ds18b20_ctl(struct file * file,unsigned int cmd,unsigned long num)
{


	if(cmd){    //read
	
		printk("k_tmp = %d\n",ds18b20_tmp());		
	}

	return 0;
	
	error1:
		printk("read error \n");
		return -1;

}

ssize_t ds18b20_read(struct file *dev, char __user *in_user, size_t size, loff_t * ppos)
{

	char p[7] = {0};
	
	uint32_t data = 0;

	data = ds18b20_tmp();

	//long_to_char(data, p);

	
	if (size > sizeof(uint32_t)){
		printk("size too big!\n");
		return -1;
	}

	if (copy_to_user(in_user, &data, sizeof(data))){
	 
		return -EFAULT;
	  }
	 
	return 0;
}

struct file_operations ds18b20_fops = {

		.unlocked_ioctl= ds18b20_ctl,
		.read = ds18b20_read,
		
};


struct miscdevice  ds18b20_misc={

		.minor = 101,
		.name = "misc_ds18b20",
		.fops = &ds18b20_fops,

};

static int ds18b20_probe(struct platform_device *pdev)
{
	
	int re = -1;
	
	printk("start probe!!!!!!!!!! \n");
	
	//ds18_gpio = of_get_named_gpio(pdev->dev.of_node, "gpios", 0);
	ds18_gpio = 57;
	
	
	printk("gpio_num = %d\n", ds18_gpio);

	//re = devm_gpio_request_one(&dev->dev, ds18_gpio,  GPIOF_OUT_INIT_LOW, "ds18b20""ds18b20");
	
	re = gpio_request(ds18_gpio, "ds18b20");

	//if (re) return -1;

	//拉高总线
	gpio_direction_output(ds18_gpio, 1);

	

	re = ds18_reset();            //检测是否存在
	
	
	if (!re){
				
		printk("finded ds18b20 \n");

		re = misc_register(&ds18b20_misc);
	
		if(re < 0)
			printk("misc register error! %d", re);
		
		
		return 0;
	
	}else{
		
		gpio_free(GPIO_DS18B20);
		
		printk("no find ds18b20 \n");
		
		return -1;
	}
	


	

	return 0;
}


static int ds18b20_drv_remove(struct platform_device *pdev)
{

	gpio_free(ds18_gpio);

	misc_deregister(&ds18b20_misc);
	
	return 0;
}


static struct platform_driver ds18b20_driver = {
	.driver	= {
		.name    = "yin,ds18b20",
		.owner	 = THIS_MODULE,
		
	},
	.probe   = ds18b20_probe,
	.remove  = ds18b20_drv_remove,
	
};


module_platform_driver(ds18b20_driver);

MODULE_LICENSE("GPL");
